﻿using System.Collections.Generic;
using System.IO;



//This is the First version of a somewhat workable gedcom reader.
//
// By ROBERT BARBROW
// VERSION  1.0
//
//
//    It was built to map out relationship between members in a given gedcom file.
//It will track full name, sex, birthday And type of relation to other
// individuals ( CHILD PARENT).

//I hope to add more functionally later such as reading in more data about the 
//individuals and families ( aka death day, education,  married/divorce etc) in later release.

//I also hope to create a portion to write to a gedcom file if needed. I don't know if that 
//would be such a good idea because i hate gedcoms stinking guts but I don't know of a 
//standard xml format yet that will be accepted by all genealogical programs 




namespace GedcomReader
{

    class Gedcom
    {
        private string GedcomText = "";

        public List<Individual> Individuals = new List<Individual>();
        public List<Family> Families = new List<Family>();
        public List<Pedigree> Pedigrees = new List<Pedigree>();


        public Gedcom(string fileName)
        {
            using (StreamReader SR = new StreamReader(fileName))
            {
                GedcomText = SR.ReadToEnd();
            }
            ReadGedcom();

        }

        private void ReadGedcom()
        {
            string[] Nodes = GedcomText.Replace("\r\n0 ", "\u0646").Split('\u0646');


           
            foreach (string Node in Nodes)
            {
                string[] SubNode = Node.Replace("\r\n", "\r").Split('\r');
                if (SubNode[0].Contains("INDI"))
                {
                    Individuals.Add(ExtractINDI(SubNode));
                }
                else if (SubNode[0].Contains("FAM"))
                {
                    Families.Add(ExtractFAM(SubNode));
                }
                else if (SubNode[0].Contains("PEDIGREELINK "))
                { 
                    Pedigrees.Add(ExtractPED(SubNode));
                }
            }
        }

        private Pedigree ExtractPED(string[] Node)
        {
            Pedigree P = new Pedigree();
            foreach (string S in Node)
            {
                if (S.Contains("PEDIGREE_LINK "))
                {
                    P.Pedigree_Type = S.Replace("1 PEDIGREE_LINK ", "").Trim();
                }
                else if (S.Contains("FAMILY "))
                {
                    P.FamilyID = S.Replace("1 FAMILY ", "").Replace("@","").Trim();
                }
                else if (S.Contains("INDIVIDUAL "))
                {
                    P.IndividualID = S.Replace("1 INDIVIDUAL ", "").Replace("@", "").Trim();
                }
            }
           
            return P;
        }

        private Family ExtractFAM(string[] Node)
        {
            string sFID = Node[0].Replace("@ FAM", "");
            string sID = "";
            string sType = "";
            foreach (string Line in Node)
            {
                // If node is HUSB
                if (Line.Contains("1 HUSB "))
                {
                    sType = "PAR";
                    sID = Line.Replace("1 HUSB ", "").Replace("@", "").Trim();
                }
                //If node for Wife
                else if (Line.Contains("1 WIFE "))
                {
                    sType = "PAR";
                    sID = Line.Replace("1 WIFE ", "").Replace("@", "").Trim();
                }
                //if node for multi children
                else if (Line.Contains("1 CHIL "))
                {
                    sType = "CHIL";
                    sID = Line.Replace("1 CHIL ", "").Replace("@", "");
                }
            }
            Family Fam = new Family(sFID, sType, sID);
            return Fam;
        }

        private Individual ExtractINDI(string[] Node)
        {
            //string[] SubNode = Node.Replace("\r\n", "\r").Split('\r');
            //If a individual is found
            //INDI I = new INDI();
            Individual I = new Individual();
            if (Node[0].Contains("INDI"))
            {
                //Create new Structure

                //Add the ID number and remove extra formating
                I.ID = Node[0].Replace("@", "").Replace(" INDI", "").Trim();
                //Find the name remove extra formating for last name
                I.Name = Node[FindIndexinArray(Node, "NAME")].Replace("1 NAME", "").Replace("/", "").Trim();
                //Find Sex and remove extra formating
                I.Sex = Node[FindIndexinArray(Node, "SEX")].Replace("1 SEX ", "").Trim();

                //Deterine if there is a brithday -1 means no
                int BirthTest = FindIndexinArray(Node, "1 BIRT ");
                if (BirthTest != -1)
                {
                    // add birthday to Struct 
                    I.BDay = Node[BirthTest + 1].Replace("2 DATE ", "").Trim();
                }

                // deterimin if there is a death tag will return -1 if not found

                int DeathTest = FindIndexinArray(Node, "1 DEAT ");
                if (DeathTest != -1)
                {
                    //convert Y or N to true or false ( defaults to False so no need to change unless Y is found.
                    if (Node[DeathTest].Replace("1 DEAT ", "").Trim() == "Y")
                    {
                        //set death
                        I.Dead = true;
                    }
                }
                foreach (string cell in Node)
                {
                    if (cell.Contains("1 FAMS"))
                    {
                        I.FamS = cell.Replace("1 FAMS ", "").Replace("@", "").Trim();
                    }
                    else if (cell.Contains("1 FAMC"))
                    {
                        I.FamC = cell.Replace("1 FAMC ", "").Replace("@", "").Trim();
                    }
                }
            }
            return I;
        }

        private int FindIndexinArray(string[] Arr, string search)
        {
            int Val = -1;
            for (int i = 0; i < Arr.Length; i++)
            {
                if (Arr[i].Contains(search))
                {
                    Val = i;
                }
            }
            return Val;
        }
    }

    class Individual
    {
        private string myName;
        private string myID;
        private bool myDead;
        private string mySex;
        private string myBday;
        private List<string> ListFamS = new List<string>();
        private List<string> ListFamC = new List<string>();

        public string Name
        {
            get
            {
                return myName;
            }
            set
            {
                myName = value;
            }
        }
        public string ID
        {
            get
            {
                return myID;
            }
            set
            {
                myID = value;
            }
        }
        public bool Dead
        {
            get
            {
                return myDead;
            }
            set
            {
                myDead = value;
            }
        }
        public string Sex
        {
            get
            {
                return mySex;
            }
            set
            {
                mySex = value;
            }
        }
        public string BDay
        {
            get
            {
                return myBday;
            }
            set
            {
                myBday = value;
            }
        }
        public string FamS
        {
            set
            {
                ListFamS.Add(value);
            }
        }
        public string FamC
        {

            set
            {
                ListFamC.Add(value);
            }
        }

        public List<string> AllFamS
        {
            get
            {
                return ListFamS;
            }
        }
        public List<string> AllFamC
        {
            get
            {
                return ListFamC;
            }
        }
    }

    class Pedigree
    {
        string myPedigree_Type = "";
        string myFamilyID = "";
        string myIndividualID = "";
        
        public Pedigree()
        {

        }
        public Pedigree(string indiviualID, string PedType, string familyID)
        {

            myPedigree_Type = PedType;
            myFamilyID = familyID;
            myIndividualID = indiviualID;

        }
        public string IndividualID
        {
            get
            {
                return myIndividualID;
            }
            set
            {
                myIndividualID = value;
            }
        }
        public string FamilyID
        {
            get
            {
                return myFamilyID;
            }
            set
            {
                myFamilyID = value;
            }
        }
        public string Pedigree_Type
        {
            get
            {
                return myPedigree_Type;
            }
            set
            {
                myPedigree_Type = value;
            }
        }
    }

    class Family
    {
        public Family(string FamID, string Type, string IndiID)
        {
            myFamID = FamID;
            myIndiID = IndiID;
            myType = Type;
        }
        public Family()
        {

        }


        string myFamID;
        string myType;
        string myIndiID;


        public string FamID
        {
            get
            {
                return myFamID;
            }
            set
            {
                myFamID = value;
            }
        }
        public string Type
        {
            get
            {
                return myType;
            }
            set
            {
                myType = value;
            }
        }
        public string IndiID
        {
            get
            {
                return myIndiID;
            }
            set
            {
                myIndiID = value;
            }
        }
    }
}

